/* extcap_argument.cpp
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include <extcap_argument.h>

#include <QObject>
#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QDateTimeEdit>
#include <QIntValidator>
#include <QDoubleValidator>
#include <QCheckBox>
#include <QButtonGroup>
#include <QBoxLayout>
#include <QRadioButton>
#include <QComboBox>
#include <QPushButton>
#include <QMargins>
#include <QVariant>
#include <QAbstractItemModel>
#include <QStringList>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <QRegularExpression>

#include <glib.h>

#include <extcap.h>
#include <epan/prefs.h>
#include <epan/prefs-int.h>
#include <wsutil/wslog.h>
#include <ui/qt/utils/color_utils.h>
#include <ui/qt/utils/qt_ui_utils.h>

#include <extcap_parser.h>
#include <extcap_argument_file.h>
#include <extcap_argument_multiselect.h>

#include <ui/qt/extcap_options_dialog.h>

ExtArgTimestamp::ExtArgTimestamp(extcap_arg * argument, QObject * parent) :
    ExtcapArgument(argument, parent), tsBox(0) {}

QWidget * ExtArgTimestamp::createEditor(QWidget * parent)
{
    QString text = defaultValue();

    if (_argument->pref_valptr && strlen(*_argument->pref_valptr))
    {
        QString storeValue(*_argument->pref_valptr);
        text = storeValue.trimmed();
    }

    ts = QDateTime::fromSecsSinceEpoch(text.toInt());
    tsBox = new QDateTimeEdit(ts, parent);
    tsBox->setDisplayFormat(QLocale::system().dateTimeFormat());
    tsBox->setCalendarPopup(true);
    tsBox->setAutoFillBackground(true);

    if (_argument->tooltip != NULL)
        tsBox->setToolTip(QString().fromUtf8(_argument->tooltip));

    connect(tsBox, &QDateTimeEdit::dateTimeChanged, this, &ExtArgTimestamp::onDateTimeChanged);

    return tsBox;
}

void ExtArgTimestamp::onDateTimeChanged(QDateTime t)
{
    ts = t;
    emit valueChanged();
}

QString ExtArgTimestamp::defaultValue()
{
    return QString::number(QDateTime::currentDateTime().toSecsSinceEpoch());
}

bool ExtArgTimestamp::isValid()
{
    bool valid = true;

    if (value().length() == 0 && isRequired())
        valid = false;

    return valid;
}

QString ExtArgTimestamp::value()
{
    return QString::number(ts.toSecsSinceEpoch());
}

QString ExtArgTimestamp::prefValue()
{
    return value();
}

bool ExtArgTimestamp::isSetDefaultValueSupported()
{
    return true;
}

void ExtArgTimestamp::setDefaultValue()
{
    QDateTime t;

    t = QDateTime::fromSecsSinceEpoch(defaultValue().toInt());
    tsBox->setDateTime(t);
}



ExtArgSelector::ExtArgSelector(extcap_arg * argument, QObject * parent) :
        ExtcapArgument(argument, parent), boxSelection(0) {}

QWidget * ExtArgSelector::createEditor(QWidget * parent)
{
    QWidget * editor = new QWidget(parent);
    QHBoxLayout * layout = new QHBoxLayout();
    QMargins margins = layout->contentsMargins();
    layout->setContentsMargins(0, margins.top(), 0, margins.bottom());

    boxSelection = new QComboBox(parent);
    boxSelection->setToolTip(QString().fromUtf8(_argument->tooltip));
    layout->addWidget(boxSelection);

    if (values.length() > 0)
    {
        ExtcapValueList::const_iterator iter = values.constBegin();

        while (iter != values.constEnd())
        {
            boxSelection->addItem((*iter).value(), (*iter).call());
            ++iter;
        }
    }

    setDefaultValue();

    if (reload())
    {
        QString btnText(tr("Reload data"));
        if (_argument->placeholder)
            btnText = QString(_argument->placeholder);

        QPushButton * reloadButton = new QPushButton(btnText, editor);
        layout->addWidget(reloadButton);
        reloadButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
        boxSelection->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);

        connect(reloadButton, &QPushButton::clicked, this, &ExtArgSelector::onReloadTriggered);
    }

#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
    connect (boxSelection, &QComboBox::currentIndexChanged, this, &ExtArgSelector::onIntChanged);
#else
    connect (boxSelection, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ExtArgSelector::onIntChanged);
#endif

    editor->setLayout(layout);

    return editor;
}

void ExtArgSelector::onReloadTriggered()
{
    int counter = 0;
    int selected = -1;

    QString call = boxSelection->currentData().toString();
    const char *prefval = (_argument->pref_valptr && strlen(*_argument->pref_valptr)) ? *_argument->pref_valptr : NULL;
    QString stored(prefval ? prefval : "");
    if (call != stored)
        stored = call;

    if (reloadValues() && values.length() > 0)
    {
        boxSelection->clear();

        ExtcapValueList::const_iterator iter = values.constBegin();

        while (iter != values.constEnd())
        {
            boxSelection->addItem((*iter).value(), (*iter).call());

            if (stored.compare((*iter).call()) == 0)
                selected = counter;
            else if ((*iter).isDefault() && selected == -1)
                selected = counter;

            counter++;
            ++iter;
        }

        if (selected > -1 && selected < boxSelection->count())
            boxSelection->setCurrentIndex(selected);
    }
}

bool ExtArgSelector::isValid()
{
    bool valid = true;

    if (value().length() == 0 && isRequired())
        valid = false;

    if (boxSelection)
    {
        QString lblInvalidColor = ColorUtils::fromColorT(prefs.gui_text_invalid).name();
        QString cmbBoxStyle("QComboBox { background-color: %1; } ");
        boxSelection->setStyleSheet(cmbBoxStyle.arg(valid ? QString("") : lblInvalidColor));
    }

    return valid;
}

QString ExtArgSelector::value()
{
    if (boxSelection == 0)
        return QString();

    QVariant data = boxSelection->currentData();

    return data.toString();
}

bool ExtArgSelector::isSetDefaultValueSupported()
{
    return true;
}

void ExtArgSelector::setDefaultValue()
{
    int counter = 0;
    int selected = -1;

    const char *prefval = (_argument->pref_valptr && strlen(*_argument->pref_valptr)) ? *_argument->pref_valptr : NULL;
    QString stored(prefval ? prefval : "");

    if (values.length() > 0)
    {
        ExtcapValueList::const_iterator iter = values.constBegin();

        while (iter != values.constEnd())
        {
            if (!prefval && (*iter).isDefault())
                selected = counter;
            else if (prefval && stored.compare((*iter).call()) == 0)
                selected = counter;

            counter++;
            ++iter;
        }

        if (selected > -1 && selected < boxSelection->count())
            boxSelection->setCurrentIndex(selected);
    }

}


ExtArgEditSelector::ExtArgEditSelector(extcap_arg * argument, QObject * parent) :
        ExtArgSelector(argument, parent) {}

QWidget * ExtArgEditSelector::createEditor(QWidget * parent)
{
    QWidget *editor = ExtArgSelector::createEditor(parent);

    boxSelection->setEditable(true);
    boxSelection->setInsertPolicy(QComboBox::NoInsert);

    return editor;
}

QString ExtArgEditSelector::value()
{
    if (boxSelection == nullptr) {
        return QString();
    }

    if (boxSelection->currentIndex() > -1) {
        return ExtArgSelector::value();
    }

    return boxSelection->currentText();
}

void ExtArgEditSelector::setDefaultValue()
{
    ExtArgSelector::setDefaultValue();

    if (boxSelection == nullptr) {
        return;
    }

    const char *prefval = (_argument->pref_valptr && strlen(*_argument->pref_valptr)) ? *_argument->pref_valptr : NULL;
    QString stored(prefval ? prefval : "");
    QVariant data = boxSelection->currentData();

    if (data.toString() != stored) {
        // createEditor may not have been called at this point?
        boxSelection->setEditable(true);
        boxSelection->setInsertPolicy(QComboBox::NoInsert);
        boxSelection->setEditText(stored);
    }
}


ExtArgRadio::ExtArgRadio(extcap_arg * argument, QObject * parent) :
        ExtcapArgument(argument, parent), selectorGroup(0), callStrings(0) {}

ExtArgRadio::~ExtArgRadio() {
    if (callStrings != nullptr)
        delete callStrings;
}

QWidget * ExtArgRadio::createEditor(QWidget * parent)
{
    int count = 0;

    selectorGroup = new QButtonGroup(parent);
    QWidget * radioButtons = new QWidget;
    QVBoxLayout * vrLayout = new QVBoxLayout();
    QMargins margins = vrLayout->contentsMargins();
    vrLayout->setContentsMargins(0, 0, 0, margins.bottom());
    if (callStrings != 0)
        delete callStrings;

    callStrings = new QList<QString>();

    if (values.length() > 0)
    {
        ExtcapValueList::const_iterator iter = values.constBegin();

        while (iter != values.constEnd())
        {
            QRadioButton * radio = new QRadioButton((*iter).value());
            QString callString = (*iter).call();
            callStrings->append(callString);

            connect(radio, &QRadioButton::clicked, this, &ExtArgRadio::onBoolChanged);
            selectorGroup->addButton(radio, count);

            vrLayout->addWidget(radio);
            count++;

            ++iter;
        }
    }

    setDefaultValue();

    radioButtons->setLayout(vrLayout);

    return radioButtons;
}

QString ExtArgRadio::value()
{
    int idx = 0;
    if (selectorGroup == 0 || callStrings == 0)
        return QString();

    idx = selectorGroup->checkedId();
    if (idx > -1 && callStrings->length() > idx)
        return callStrings->at(idx);

    return QString();
}

bool ExtArgRadio::isValid()
{
    bool valid = true;
    int idx = 0;

    if (isRequired())
    {
        if (selectorGroup == 0 || callStrings == 0)
            valid = false;
        else
        {
            idx = selectorGroup->checkedId();
            if (idx == -1 || callStrings->length() <= idx)
                valid = false;
        }
    }

    /* If nothing is selected, but a selection is required, the only thing that
     * can be marked is the label */
    QString lblInvalidColor = ColorUtils::fromColorT(prefs.gui_text_invalid).name();
    _label->setStyleSheet (label_style.arg(valid ? QString("") : lblInvalidColor));

    return valid;
}

bool ExtArgRadio::isSetDefaultValueSupported()
{
    return true;
}

void ExtArgRadio::setDefaultValue()
{
    int counter = 0;
    int selected = 0;

    const char *prefval = (_argument->pref_valptr && strlen(*_argument->pref_valptr)) ? *_argument->pref_valptr : NULL;
    QString stored(prefval ? prefval : "");

    if (values.length() > 0)
    {
        ExtcapValueList::const_iterator iter = values.constBegin();

        while (iter != values.constEnd())
        {
            if (!prefval && (*iter).isDefault())
                selected = counter;
            else if (prefval && stored.compare((*iter).call()) == 0)
                selected = counter;

            counter++;
            ++iter;
        }

        ((QRadioButton*)(selectorGroup->button(selected)))->setChecked(true);
    }
}



ExtArgBool::ExtArgBool(extcap_arg * argument, QObject * parent) :
        ExtcapArgument(argument, parent), boolBox(0) {}

QWidget * ExtArgBool::createLabel(QWidget * parent)
{
    return new QWidget(parent);
}

QWidget * ExtArgBool::createEditor(QWidget * parent)
{
    bool state = defaultBool();

    boolBox = new QCheckBox(QString().fromUtf8(_argument->display), parent);
    if (_argument->tooltip != NULL)
        boolBox->setToolTip(QString().fromUtf8(_argument->tooltip));

    const char *prefval = (_argument->pref_valptr && strlen(*_argument->pref_valptr)) ? *_argument->pref_valptr : NULL;
    if (prefval)
    {
        QRegularExpression regexp(EXTCAP_BOOLEAN_REGEX);
        QRegularExpressionMatch match = regexp.match(QString(prefval[0]));
        bool savedstate = match.hasMatch();
        if (savedstate != state)
            state = savedstate;
    }

    boolBox->setCheckState(state ? Qt::Checked : Qt::Unchecked);

#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
    connect (boolBox, &QCheckBox::checkStateChanged, this, &ExtArgBool::onIntChanged);
#else
    connect (boolBox, &QCheckBox::stateChanged, this, &ExtArgBool::onIntChanged);
#endif

    return boolBox;
}

QString ExtArgBool::call()
{
    if (boolBox == NULL)
        return QString("");

    if (_argument->arg_type == EXTCAP_ARG_BOOLEAN)
        return ExtcapArgument::call();

    return QString(boolBox->checkState() == Qt::Checked ? _argument->call : "");
}

QString ExtArgBool::value()
{
    if (boolBox == NULL || _argument->arg_type == EXTCAP_ARG_BOOLFLAG)
        return QString();
    return QString(boolBox->checkState() == Qt::Checked ? "true" : "false");
}

QString ExtArgBool::prefValue()
{
    if (boolBox == NULL)
        return QStringLiteral("false");
    return QString(boolBox->checkState() == Qt::Checked ? "true" : "false");
}

bool ExtArgBool::isValid()
{
    /* A bool is always valid, but the base function checks on string length,
     * which will fail with boolflags */
    return true;
}

bool ExtArgBool::defaultBool()
{
    bool result = false;

    if (_argument)
    {
        if (extcap_complex_get_bool(_argument->default_complex) == true)
            result = true;
    }

    return result;
}

QString ExtArgBool::defaultValue()
{
    return defaultBool() ? QStringLiteral("true") : QStringLiteral("false");
}

bool ExtArgBool::isSetDefaultValueSupported()
{
    return true;
}

void ExtArgBool::setDefaultValue()
{
    boolBox->setCheckState(defaultBool() ? Qt::Checked : Qt::Unchecked);
}



ExtArgText::ExtArgText(extcap_arg * argument, QObject * parent) :
    ExtcapArgument(argument, parent), textBox(0)
{
}

QWidget * ExtArgText::createEditor(QWidget * parent)
{
    QString text = defaultValue();

    /* Prefs can contain empty string. We accept it. */
    if (_argument->pref_valptr && (*_argument->pref_valptr))
    {
        QString storeValue(*_argument->pref_valptr);
        text = storeValue.trimmed();
    }

    textBox = new QLineEdit(text, parent);

    if (_argument->tooltip != NULL)
        textBox->setToolTip(QString().fromUtf8(_argument->tooltip));

    if (_argument->placeholder != NULL)
        textBox->setPlaceholderText(QString().fromUtf8(_argument->placeholder));

    if (_argument->arg_type == EXTCAP_ARG_PASSWORD)
        textBox->setEchoMode(QLineEdit::PasswordEchoOnEdit);

    connect(textBox, &QLineEdit::textChanged, this, &ExtArgText::onStringChanged);

    return textBox;
}

QString ExtArgText::value()
{
    if (textBox == 0)
        return QString();

    return textBox->text();
}

bool ExtArgText::isValid()
{
    bool valid = true;

    if (isRequired() && value().length() == 0)
        valid = false;

    /* Does the validator, if any, consider the value valid?
     *
     * If it considers it an "intermediate" value, rather than an "invalid"
     * value, the user will be able to transfer the input focus to another
     * widget, and, as long as all widgets have values for which isValid()
     * is true, they wil be able to click the "Start" button.
     *
     * For QIntValidator(), used for integral fields with minimum and
     * maximum values, a value that's larger than the maximum but has
     * the same number of digits as the maximum is "intermediate" rather
     * than "invalid", so the user will be able to cause that value to
     * be passed to the extcap module; see bug 16510.
     *
     * So we explicitly call the hasAcceptableInput() method on the
     * text box; that returns false if the value is not "valid", and
     * that includes "intermediate" values.
     *
     * This way, 1) non-colorblind users are informed that the value
     * is invalid by the text box background being red (perhaps the
     * user isn't fully colorblind, or perhaps the background is a
     * noticeably different grayscale), and 2) the user won't be able
     * to start the capture until they fix the problem.
     *
     * XXX - it might be nice to have some way of indicating to the
     * user what the problem is with the value - alert box?  Tooltip? */
    if (!textBox->hasAcceptableInput())
        valid = false;

    /* validation should only be checked if there is a value. if the argument
     * must be present (isRequired) the check above will handle that */
    if (valid && _argument->regexp != NULL && value().length() > 0)
    {
        QString regexp = QString().fromUtf8(_argument->regexp);
        if (regexp.length() > 0)
        {
            QRegularExpression expr(regexp, QRegularExpression::UseUnicodePropertiesOption);
            if (! expr.isValid() || ! expr.match(value()).hasMatch())
                valid = false;
        }
    }

    QString lblInvalidColor = ColorUtils::fromColorT(prefs.gui_text_invalid).name();
    QString txtStyle("QLineEdit { background-color: %1; } ");
    textBox->setStyleSheet(txtStyle.arg(valid ? QString("") : lblInvalidColor));

    return valid;
}

bool ExtArgText::isSetDefaultValueSupported()
{
    return true;
}

void ExtArgText::setDefaultValue()
{
    textBox->setText(defaultValue());
}



ExtArgNumber::ExtArgNumber(extcap_arg * argument, QObject * parent) :
        ExtArgText(argument, parent) {}

QWidget * ExtArgNumber::createEditor(QWidget * parent)
{
    QString text = defaultValue();

    if (_argument->pref_valptr && strlen(*_argument->pref_valptr))
    {
        QString storeValue(*_argument->pref_valptr);
        text = storeValue;
    }

    textBox = (QLineEdit *)ExtArgText::createEditor(parent);
    textBox->disconnect(SIGNAL(textChanged(QString)));

    if (_argument->arg_type == EXTCAP_ARG_INTEGER || _argument->arg_type == EXTCAP_ARG_UNSIGNED)
    {
        QIntValidator * textValidator = new QIntValidator(parent);
        if (_argument->range_start != NULL)
        {
            int val = 0;
            if (_argument->arg_type == EXTCAP_ARG_INTEGER)
                val = extcap_complex_get_int(_argument->range_start);
            else if (_argument->arg_type == EXTCAP_ARG_UNSIGNED)
            {
                unsigned tmp = extcap_complex_get_uint(_argument->range_start);
                if (tmp > INT_MAX)
                {
                    ws_log(LOG_DOMAIN_CAPTURE, LOG_LEVEL_DEBUG, "Defined value for range_start of %s exceeds valid integer range", _argument->call);
                    val = INT_MAX;
                }
                else
                    val = (int)tmp;
            }

            textValidator->setBottom(val);
        }
        if (_argument->arg_type == EXTCAP_ARG_UNSIGNED && textValidator->bottom() < 0)
        {
            ws_log(LOG_DOMAIN_CAPTURE, LOG_LEVEL_DEBUG, "%s sets negative bottom range for unsigned value, setting to 0", _argument->call);
            textValidator->setBottom(0);
        }

        if (_argument->range_end != NULL)
        {
            int val = 0;
            if (_argument->arg_type == EXTCAP_ARG_INTEGER)
                val = extcap_complex_get_int(_argument->range_end);
            else if (_argument->arg_type == EXTCAP_ARG_UNSIGNED)
            {
                unsigned tmp = extcap_complex_get_uint(_argument->range_end);
                if (tmp > INT_MAX)
                {
                    ws_log(LOG_DOMAIN_CAPTURE, LOG_LEVEL_DEBUG, "Defined value for range_end of %s exceeds valid integer range", _argument->call);
                    val = INT_MAX;
                }
                else
                    val = (int)tmp;
            }

            textValidator->setTop(val);
        }
        textBox->setValidator(textValidator);
    }
    else if (_argument->arg_type == EXTCAP_ARG_DOUBLE)
    {
        QDoubleValidator * textValidator = new QDoubleValidator(parent);
        if (_argument->range_start != NULL)
            textValidator->setBottom(extcap_complex_get_double(_argument->range_start));
        if (_argument->range_end != NULL)
            textValidator->setTop(extcap_complex_get_double(_argument->range_end));

        textBox->setValidator(textValidator);
    }

    textBox->setText(text.trimmed());

    connect(textBox, &QLineEdit::textChanged, this, &ExtArgNumber::onStringChanged);

    return textBox;
}

QString ExtArgNumber::defaultValue()
{
    QString result;

    if (_argument != 0)
    {
        if (_argument->arg_type == EXTCAP_ARG_DOUBLE)
            result = QString::number(extcap_complex_get_double(_argument->default_complex));
        else if (_argument->arg_type == EXTCAP_ARG_INTEGER)
            result = QString::number(extcap_complex_get_int(_argument->default_complex));
        else if (_argument->arg_type == EXTCAP_ARG_UNSIGNED)
            result = QString::number(extcap_complex_get_uint(_argument->default_complex));
        else if (_argument->arg_type == EXTCAP_ARG_LONG)
            result = QString::number(extcap_complex_get_long(_argument->default_complex));
        else
        {
            QString defValue = ExtcapArgument::defaultValue();
            result = defValue.length() > 0 ? defValue : QString();
        }
    }

    return result;
}

ExtcapValue::~ExtcapValue() {}

void ExtcapValue::setChildren(ExtcapValueList children)
{
    ExtcapValueList::iterator iter = children.begin();
    while (iter != children.end())
    {
        (*iter)._depth = _depth + 1;
        ++iter;
    }

    _children.append(children);
}

ExtcapArgument::ExtcapArgument(QObject *parent) :
        QObject(parent), _argument(0), _label(0), _number(0),
        label_style(QStringLiteral("QLabel { color: %1; }"))
{
}

ExtcapArgument::ExtcapArgument(extcap_arg * argument, QObject *parent) :
        QObject(parent), _argument(argument), _label(0),
        label_style(QStringLiteral("QLabel { color: %1; }"))
{
    _number = argument->arg_num;

    if (_argument->values != 0)
    {
        ExtcapValueList elements = loadValues(QString(""));
        if (elements.length() > 0)
            values.append(elements);
    }
}

ExtcapArgument::ExtcapArgument(const ExtcapArgument &obj) :
        QObject(obj.parent()), _argument(obj._argument), _label(0),
        label_style(QStringLiteral("QLabel { color: %1; }"))
{
    _number = obj._argument->arg_num;

    if (_argument->values != 0)
    {
        ExtcapValueList elements = loadValues(QString(""));
        if (elements.length() > 0)
            values.append(elements);
    }
}

ExtcapValueList ExtcapArgument::loadValues(QString parent)
{
    if (_argument == 0 || _argument->values == 0)
        return ExtcapValueList();

    GList * walker = 0;
    extcap_value * v;
    ExtcapValueList elements;

    for (walker = g_list_first((GList *)(_argument->values)); walker != NULL ; walker = walker->next)
    {
        v = (extcap_value *) walker->data;
        if (v == NULL || v->display == NULL || v->call == NULL)
            break;

        QString valParent = QString().fromUtf8(v->parent);

        if (parent.compare(valParent) == 0)
        {

            QString display = QString().fromUtf8(v->display);
            QString call = QString().fromUtf8(v->call);

            ExtcapValue element = ExtcapValue(display, call,
                            v->enabled == true, v->is_default == true);

            if (!call.isEmpty())
                element.setChildren(this->loadValues(call));

            elements.append(element);
        }
    }

    return elements;
}

bool ExtcapArgument::reloadValues()
{
    if (! qobject_cast<ExtcapOptionsDialog*> (parent()) )
        return false;

    ExtcapOptionsDialog * dialog = qobject_cast<ExtcapOptionsDialog*>(parent());
    ExtcapValueList list = dialog->loadValuesFor(_argument->arg_num, _argument->call);

    if (list.size() > 0)
    {
        values.clear();
        values << list;

        return true;
    }

    return false;
}

ExtcapArgument::~ExtcapArgument() {
    extcap_free_arg(_argument);
}

QWidget * ExtcapArgument::createLabel(QWidget * parent)
{
    if (_argument == 0 || _argument->display == 0)
        return 0;

    QString lblInvalidColor = ColorUtils::fromColorT(prefs.gui_text_invalid).name();

    QString text = QString().fromUtf8(_argument->display);

    if (_label == 0)
        _label = new QLabel(text, parent);
    else
        _label->setText(text);

    _label->setProperty("isRequired", QString(isRequired() ? "true" : "false"));

    _label->setStyleSheet (label_style.arg(QString("")));

    if (_argument->tooltip != 0)
        _label->setToolTip(QString().fromUtf8(_argument->tooltip));

    return (QWidget *)_label;
}

QWidget * ExtcapArgument::createEditor(QWidget *)
{
    return 0;
}

QString ExtcapArgument::call()
{
    return QString(_argument->call);
}

QString ExtcapArgument::value()
{
    return QString();
}

QString ExtcapArgument::prefValue()
{
    return value();
}

void ExtcapArgument::resetValue()
{
    if (_argument->pref_valptr) {
        g_free(*_argument->pref_valptr);
        *_argument->pref_valptr = g_strdup("");
    }
}

bool ExtcapArgument::isValid()
{
    /* Unrequired arguments are always valid, except if validity checks fail,
     * which must be checked in an derived class, not here */
    if (! isRequired())
        return true;

    return value().length() > 0;
}

QString ExtcapArgument::defaultValue()
{
    if (_argument != 0 && _argument->default_complex != 0)
    {
        char * str = extcap_get_complex_as_string(_argument->default_complex);
        if (str != nullptr)
            return gchar_free_to_qstring(str);
    }
    return QString();
}

QString ExtcapArgument::group() const
{
    if (_argument != 0 && _argument->group != 0)
        return QString(_argument->group);

    return QString();
}

int ExtcapArgument::argNr() const
{
    return _number;
}

QString ExtcapArgument::prefKey(const QString & device_name)
{
    pref_t * pref = NULL;

    if (_argument == 0 || ! _argument->save)
        return QString();

    pref = extcap_pref_for_argument(device_name.toStdString().c_str(), _argument);
    if (pref != NULL)
        return QString(prefs_get_name(pref));

    return QString();
}

bool ExtcapArgument::isRequired()
{
    if (_argument != NULL)
        return _argument->is_required;

    return false;
}

bool ExtcapArgument::reload()
{
    if (_argument != NULL)
        return _argument->reload;

    return false;
}

bool ExtcapArgument::fileExists()
{
    if (_argument != NULL)
        return _argument->fileexists;

    return false;
}

bool ExtcapArgument::isDefault()
{
    if (value().compare(defaultValue()) == 0)
        return true;

    return false;
}

ExtcapArgument * ExtcapArgument::create(extcap_arg * argument, QObject *parent)
{
    if (argument == 0 || argument->display == 0)
        return 0;

    ExtcapArgument * result = 0;

    if (argument->arg_type == EXTCAP_ARG_STRING || argument->arg_type == EXTCAP_ARG_PASSWORD)
        result = new ExtArgText(argument, parent);
    else if (argument->arg_type == EXTCAP_ARG_INTEGER || argument->arg_type == EXTCAP_ARG_LONG ||
            argument->arg_type == EXTCAP_ARG_UNSIGNED || argument->arg_type == EXTCAP_ARG_DOUBLE)
        result = new ExtArgNumber(argument, parent);
    else if (argument->arg_type == EXTCAP_ARG_BOOLEAN || argument->arg_type == EXTCAP_ARG_BOOLFLAG)
        result = new ExtArgBool(argument, parent);
    else if (argument->arg_type == EXTCAP_ARG_SELECTOR)
        result = new ExtArgSelector(argument, parent);
    else if (argument->arg_type == EXTCAP_ARG_EDIT_SELECTOR)
        result = new ExtArgEditSelector(argument, parent);
    else if (argument->arg_type == EXTCAP_ARG_RADIO)
        result = new ExtArgRadio(argument, parent);
    else if (argument->arg_type == EXTCAP_ARG_FILESELECT)
        result = new ExtcapArgumentFileSelection(argument, parent);
    else if (argument->arg_type == EXTCAP_ARG_MULTICHECK)
        result = new ExtArgMultiSelect(argument, parent);
    else if (argument->arg_type == EXTCAP_ARG_TIMESTAMP)
        result = new ExtArgTimestamp(argument, parent);
    else
    {
        /* For everything else, we just print the label */
        result = new ExtcapArgument(argument, parent);
    }

    return result;
}

/* The following is a necessity, because Q_Object does not do well with multiple inheritances */
void ExtcapArgument::onStringChanged(QString)
{
    emit valueChanged();
}

void ExtcapArgument::onIntChanged(int)
{
    if (isValid())
        emit valueChanged();
}

void ExtcapArgument::onBoolChanged(bool)
{
    emit valueChanged();
}

bool ExtcapArgument::isSetDefaultValueSupported()
{
    return false;
}

void ExtcapArgument::setDefaultValue()
{
}

